package com.sxhuayuan.parking.controller.parkinglot.user;

import java.io.IOException;
import java.math.BigDecimal;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alipay.api.internal.util.codec.Base64;
import com.sxhuayuan.parking.compenent.Page;
import com.sxhuayuan.parking.compenent.Pageable;
import com.sxhuayuan.parking.compenent.web.RespMessage;
import com.sxhuayuan.parking.config.PayStatus;
import com.sxhuayuan.parking.config.Platform;
import com.sxhuayuan.parking.controller.BaseController;
import com.sxhuayuan.parking.dto.OrderRefundDTO;
import com.sxhuayuan.parking.entity.Order;
import com.sxhuayuan.parking.entity.OrderRefund;
import com.sxhuayuan.parking.entity.ParkingLotUser;
import com.sxhuayuan.parking.plugin.payment.WxPayPlugin;
import com.sxhuayuan.parking.service.OrderService;
import com.sxhuayuan.parking.service.ParkingLotUserService;
import com.sxhuayuan.parking.service.RSAService;
import com.sxhuayuan.parking.utils.CSVUtil;
import com.sxhuayuan.parking.utils.DateUtils;
import com.sxhuayuan.parking.utils.SettingUtils;

@RestController("parkingLotUserOrderControlelr")
@RequestMapping("/parkinglotuser/order")
public class OrderController extends BaseController {

	@Resource(name = "orderServiceImpl")
	OrderService service;
	@Resource(name = "parkingLotUserServiceImpl")
	ParkingLotUserService parkingLotUserService;
	@Autowired
	RSAService rsaService;
	@Resource(name = "wxPayPlugin")
	WxPayPlugin wxPayPlugin;
	private static Logger log = LoggerFactory.getLogger(OrderController.class);

	/** 一天的毫秒值 */
	private static final Long DAY_TIME = 24 * 60 * 60 * 1000L;
	/** 报表导出允许最大时间范围：天 */
	private static final int DAY = 31;
	/** 下载链接超时时间：10分钟 */
	private static final Long TIMEOUT = 5 * 60 * 1000L;

	/**
	 * 分页条件查询订单
	 */
	@PostMapping("/list")
	public RespMessage list(@RequestBody Pageable pageable) {
		ParkingLotUser current = parkingLotUserService.getCurrent();
		if (current == null) {
			return invalidToken();
		}
		Page<Order> page = service.findPage(pageable, current);
		return successResp(page);
	}

	/**
	 * 分页查询订单的金额统计
	 *
	 * @return 订单金额
	 */
	@PostMapping("/countmoney")
	public RespMessage getCountMoney(@RequestBody Pageable pageable) {
		ParkingLotUser current = parkingLotUserService.getCurrent();
		if (current == null) {
			return invalidToken();
		}
		return successResp(service.statistical(pageable, current));
	}

	/**
	 * 报表导出
	 *
	 * @param plateNum
	 *            车牌号
	 * @param payStatus
	 *            支付状态，默认为支付成功
	 * @param platform
	 *            支付方式
	 * @param beginTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @param t
	 *            时间戳
	 * @return Excel文件
	 */
	@GetMapping("/download_report")
	public RespMessage downloadReport(HttpServletResponse response, String plateNum, PayStatus payStatus, Platform platform, Date beginTime, Date endTime, Long t) throws IOException {
		long l = System.currentTimeMillis();
		ParkingLotUser current = parkingLotUserService.getCurrent();
		if (current == null) {
			return invalidToken();
		} else if (t == null || t > System.currentTimeMillis()) {
			return RespMessage.error("时间戳有误");
		} else if (System.currentTimeMillis() - t > TIMEOUT) {
			return RespMessage.error("链接已失效");
		} else if (beginTime == null || endTime == null) {
			return RespMessage.error("请选择时间范围");
		} else if ((endTime.getTime() - beginTime.getTime()) / DAY_TIME > DAY) {
			return RespMessage.error("时间跨度不能超过" + DAY + "天");
		}
		List<Order> list = service.findByDownloadReport(current, plateNum, payStatus, platform, beginTime, endTime);
		if (list == null || list.size() == 0) {
			return RespMessage.error("所选条件未查询到数据");
		}
		String fileName = DateUtils.format(beginTime, "yyyy年MM月dd日") + "至" + DateUtils.format(endTime, "yyyy年MM月dd日") + "订单报表";
		String s = buildOrderStr(list);
		log.debug("csv下载耗时：{}毫秒", System.currentTimeMillis() - l);
		CSVUtil.sendcsv(s, fileName, response);
		return null;
	}

	/** 将订单拼接成字符串 */
	private String buildOrderStr(List<Order> list) {
		StringBuilder sb = new StringBuilder();
		sb.append("车牌号码,金额,手续费,退款金额,停车场,停车时长,进场时间,下单时间,支付时间,支付状态,支付类别,订单号码,车场订单号,华贝订单号,下单ip,备注\n");
		for (Order order : list) {
			sb.append(order.getCarPlate()).append(",");
			sb.append(order.getMoney()).append(",");
			sb.append(order.getServiceCharge()).append(",");
			sb.append(order.getRefundMoney()).append(",");
			sb.append(order.getParkingLotName()).append(",");
			sb.append(getParkingTime(order)).append(",");
			sb.append(DateUtils.format(order.getEntertime())).append(",");
			sb.append(DateUtils.format(order.getCreateDate())).append(",");
			sb.append(DateUtils.format(order.getPaytime())).append(",");
			sb.append(getPayStatus(order.getPayStatus())).append(",");
			sb.append(getPlatform(order.getPlatform())).append(",");
			sb.append(order.getSn()).append(",");
			sb.append(order.getLotOrderNo()).append(",");
			sb.append(order.getTradeNo()).append(",");
			sb.append(order.getIp()).append(",");
			sb.append(order.getRemark()).append("\n");
		}
		return sb.toString();
	}

	/**
	 * 退款，提交前需要先获取rsa公钥，加密登录密码后提交
	 */
	@RequestMapping("/refund")
	public RespMessage refund(@RequestBody OrderRefundDTO dto, HttpServletRequest request) {
		Order order = service.findBySn(dto.getTradeNo());
		if (order == null || order.getPayStatus() != PayStatus.success) {
			return RespMessage.error("订单不存在或未支付");
		}
		BigDecimal refundMoney = SettingUtils.get().setScale(new BigDecimal(dto.getRefundMoney()));
		if (BigDecimal.ZERO.compareTo(refundMoney) >= 0) {
			return RespMessage.error("退款金额必须大于0！");
		}
		if (order.getPaidMoney().compareTo(refundMoney) < 0) {
			return RespMessage.error("可退款金额不足: " + String.format("%.2f", order.getPaidMoney()));
		}
		ParkingLotUser current = parkingLotUserService.getCurrent();
		if (current == null) {
			return RespMessage.error(RespMessage.Status.NON_PERMISSION, "登录失效");
		} else if (StringUtils.isEmpty(current.getRefundPass())) {
			return RespMessage.error("未设置退款密码，请先点击右上角头像修改退款密码！");
		}
		// 校验退款密码
		String pswd = rsaService.decrypt(dto.getPswd(), request);
		if (!StringUtils.equals(DigestUtils.md5Hex(pswd), current.getRefundPass())) {
			return RespMessage.error("密码错误");
		}
		OrderRefund refund = wxPayPlugin.refund(order, refundMoney, dto.getNote());
		if (refund.getIsSuccess()) {
			return RespMessage.success("退款成功");
		} else {
			return RespMessage.error("退款失败: " + refund.getError());
		}
	}

	/**
	 * 获取公钥
	 * 
	 * @param request
	 *            req
	 * @return 公钥字符串
	 */
	@RequestMapping("/refund/rsa")
	public RespMessage getRsa(HttpServletRequest request) {
		RSAPublicKey publicKey = rsaService.generateKey(request);
		String s = new String(Base64.encodeBase64(publicKey.getEncoded()));
		return successResp(s);
	}

	/** 获取支付状态 */
	private String getPayStatus(PayStatus status) {
		switch (status) {
		case success:
			return "支付成功";
		case notpay:
			return "未支付";
		case fail:
			return "支付失败";
		default:
			return "未知";
		}
	}

	/** 获取支付方式 */
	private String getPlatform(Platform platform) {
		if (platform == null) {
			return "未知";
		}
		switch (platform) {
		case alipay:
			return "支付宝";
		case weixin:
			return "微信";
		default:
			return "未知";
		}
	}

	/** 获取停车时长 */
	private String getParkingTime(Order order) {
		Date start = order.getEntertime();
		Date end = order.getEndtime();
		String s = "";
		if (start != null && end != null) {
			long t = DateUtils.diff(start, end, Calendar.MINUTE);
			int hour = (int) (t / 60);
			if (hour != 0) {
				s = hour + "小时" + (t % 60) + "分";
			} else {
				s = (t % 60) + "分";
			}
		}
		return s;
	}
}
